
#pragma once
#include "CudaDeviceBuffer.h";
using namespace System;

namespace GRIP
{
	namespace Cuda
	{
		/// <summary>
		/// Internal class for holding an unmanaged pointer to a host-allocated byte array.
		/// </summary>
		private class InternalCudaHostBuffer
		{
		public:
			/// <summary>
			/// Internal class for holding an unmanaged pointer to a host-allocated byte array.
			/// </summary>
			/// <param name="size">Size of the buffer in bytes</param>
			InternalCudaHostBuffer(int size);

			~InternalCudaHostBuffer();
			BYTE* buffer;
		};

		/// <summary>
		/// CudaHostBuffer is a managed wrapper for a host-allocated byte array.
		/// Memory allocated in a CudaHostBuffer is pinned and locked using cudaMallocHost,
		/// so it will never be page-swapped.
		/// </summary>
		public ref class CudaHostBuffer
		{
		public:
			/// <summary>
			/// CudaHostBuffer is a managed wrapper for a host-allocated byte array.
			/// Memory allocated in a CudaHostBuffer is pinned and locked using cudaMallocHost,
			/// so it will never be page-swapped.
			/// </summary>
			/// <param name="width">Width of the array</param>
			/// <param name="height">Height of the array</param>
			/// <param name="elementSize">Size of a single element in bytes</param>
			CudaHostBuffer(int width, int height, int elementSize);
			
			/// <summary>
			/// Returns an IntPtr to the data for use with managed code.
			/// </summary>
			/// <returns>IntPtr to the GPU array</returns>
			IntPtr Data();
			
			/// <summary>
			/// Returns a pointer to the byte array for use with unmanaged code.
			/// </summary>
			/// <returns>Pointer to the GPU array</returns>
			BYTE* Ptr();

			/// <summary>
			/// Copies data to a GPU buffer. Since memory was allocated with 
			/// cudaMallocHost and is pinned, the graphics device can perform
			/// a copy using DMA which makes it very fast.
			/// </summary>
			/// <param name="target">GPU buffer target to copy data into.</param>
			void CopyToDevice(CudaDeviceBuffer^ target);

			
			/// <summary>
			/// Copies data from a GPU buffer. Since memory was allocated with 
			/// cudaMallocHost and is pinned, the graphics device can perform
			/// a copy using DMA which makes it very fast.
			/// </summary>
			/// <param name="target">GPU buffer to copy data from.</param>
			void CopyFromDevice(CudaDeviceBuffer^ source);
			
			/// <summary>
			/// Returns the total size of the buffer in bytes.
			/// </summary>
			/// <returns>Length of the buffer in bytes</returns>
			int BufferSize();
			
			/// <summary>
			/// Returns the width of the buffer.
			/// </summary>
			/// <returns>Width of the buffer</returns>
			int GetWidth();
			
			/// <summary>
			/// Returns the height of the buffer.
			/// </summary>
			/// <returns>Height of the buffer</returns>
			int GetHeight();
		private:
			InternalCudaHostBuffer* InternalBuffer;
			IntPtr ManagedBufferPtr;
			int Size;
			int Width;
			int Height;
		};
	}
}